/*
 *Copyright 2021-2023 NERCIS
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
 */

package cn.ac.nercis.pes.service.document.report;

import cn.ac.nercis.pes.model.bo.doc.common.evaluation.SystemAssetBO;
import cn.ac.nercis.pes.model.bo.doc.common.table.asset.*;
import cn.ac.nercis.pes.model.dto.evaluation.asset.*;
import cn.ac.nercis.pes.model.dto.evaluation.prepare.PersonnelDTO;
import cn.ac.nercis.pes.model.dto.evaluation.prepare.SecurityDocumentDTO;
import cn.ac.nercis.pes.repository.model.project.SystemDO;
import cn.ac.nercis.pes.service.evaluation.AssetService;
import cn.ac.nercis.pes.service.evaluation.PersonnelService;
import cn.ac.nercis.pes.service.evaluation.SecurityDocumentService;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 报告系统资产数据服务类
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
@Service
public record ReportAssetDataService(AssetService assetService,
                                     SecurityDocumentService securityDocumentService,
                                     PersonnelService personnelService) {

    public SystemAssetBO getSystemAssetData(@NonNull SystemDO systemDO){
        try {
            return SystemAssetBO.builder()
                    .phyEnvTable(this.getPhyEnvTable(systemDO.getId()))
                    .phySecurityTable(this.getPhySecurityTable(systemDO.getId()))
                    .pwdProductTable(this.getPwdProductTable(systemDO.getId()))
                    .serverStorageTable(this.getServerStorageTable(systemDO.getId()))
                    .networkSecurityTable(this.getNetworkSecurityTable(systemDO.getId()))
                    .databaseTable(this.getDatabaseTable(systemDO.getId()))
                    .keyBusinessTable(this.getKeyBusinessTable(systemDO.getId()))
                    .keyDataTable(this.getKeyDataTable(systemDO.getId()))
                    .securityDocTable(this.getSecurityDocTable(systemDO.getId()))
                    .personnelTable(this.getPersonnelTable(systemDO.getId()))
                    .build();
        } catch (RuntimeException rEx) {
            log.error("{}/getSystemAssetData 获取数据出错：{}", this.getClass().getName(), rEx.getMessage());
            throw rEx;
        }
    }

    private List<PhyEnvReportBO> getPhyEnvTable(String systemId){
        List<PhyEnvDTO> assets = this.assetService.findPhyEnv("",systemId);
        if(CollectionUtils.isEmpty(assets)){
            return phyEnvTableByEmpty();
        }
        AtomicInteger number = new AtomicInteger(1);
        return assets.stream()
                .map(item -> PhyEnvReportBO.builder()
                        .number(String.valueOf(number.getAndIncrement()))
                        .name(item.getName())
                        .location(item.getLocation())
                        .importance(item.getImportance())
                        .build())
                .toList();
    }

    private List<PhySecurityReportBO> getPhySecurityTable(String systemId){
        List<PhySecurityDTO> assets = this.assetService.findPhySecurity("",systemId).stream()
                .sorted(Comparator.comparing((ps)->Objects.nonNull(ps.getLocation())?ps.getLocation():ps.getName()))
                .collect(Collectors.toList());
        if(CollectionUtils.isEmpty(assets)){
            return phySecurityTableByEmpty();
        }
        AtomicInteger number = new AtomicInteger(1);
        return assets.stream()
                .map(item -> PhySecurityReportBO.builder()
                        .number(String.valueOf(number.getAndIncrement()))
                        .name(item.getName())
                        .vendor(item.getVendor())
                        .location(item.getLocation())
                        .importance(item.getImportance())
                        .build())
                .toList();

    }

    private List<PwdProductReportBO> getPwdProductTable(String systemId){
        List<PwdProductDTO> assets = this.assetService.findPwdProduct("",systemId);
        if(CollectionUtils.isEmpty(assets)){
            return pwdProductTableByEmpty();
        }
        AtomicInteger number = new AtomicInteger(1);
        return assets.stream()
                .map(item -> PwdProductReportBO.builder()
                        .number(String.valueOf(number.getAndIncrement()))
                        .name(item.getName())
                        .vendor(item.getVendor())
                        .model(item.getModel())
                        .algorithm(item.getAlgorithm())
                        .count(item.getCount())
                        .use(item.getUse())
                        .build())
                .toList();
    }

    private List<ServerStorageReportBO> getServerStorageTable(String systemId){
        List<ServerStorageDTO> assets = this.assetService.findServerStorage("",systemId);
        if(CollectionUtils.isEmpty(assets)){
            return serverStorageTableByEmpty();
        }
        AtomicInteger number = new AtomicInteger(1);
        return assets.stream()
                .map(item -> ServerStorageReportBO.builder()
                        .number(String.valueOf(number.getAndIncrement()))
                        .name(item.getName())
                        .vendor(item.getVendor())
                        .model(item.getModel())
                        .osName(item.getOsName())
                        .virtual(item.getVirtual())
                        .use(item.getUse())
                        .count(item.getCount())
                        .importance(item.getImportance())
                        .build())
                .toList();
    }

    private List<NetworkSecurityReportBO> getNetworkSecurityTable(String systemId){
        List<NetworkSecurityDTO> assets = this.assetService.findNetworkSecurity("",systemId);
        if(CollectionUtils.isEmpty(assets)){
            return networkSecurityTableByEmpty();
        }
        AtomicInteger number = new AtomicInteger(1);
        return assets.stream()
                .map(item -> NetworkSecurityReportBO.builder()
                        .number(String.valueOf(number.getAndIncrement()))
                        .name(item.getName())
                        .vendor(item.getVendor())
                        .model(item.getModel())
                        .use(item.getUse())
                        .count(item.getCount())
                        .importance(item.getImportance())
                        .build())
                .toList();
    }

    private List<DatabaseReportBO> getDatabaseTable(String systemId){
        List<DatabaseDTO> assets = this.assetService.findDatabase("",systemId);
        if(CollectionUtils.isEmpty(assets)){
            return databaseTableByEmpty();
        }
        AtomicInteger number = new AtomicInteger(1);
        return assets.stream()
                .map(item -> DatabaseReportBO.builder()
                        .number(String.valueOf(number.getAndIncrement()))
                        .name(item.getName())
                        .version(item.getVersion())
                        .location(item.getLocation())
                        .function(item.getFunction())
                        .importance(item.getImportance())
                        .build())
                .toList();
    }

    private List<KeyBusinessReportBO> getKeyBusinessTable(String systemId){
        List<KeyBusinessDTO> assets = this.assetService.findKeyBusiness("",systemId);
        if(CollectionUtils.isEmpty(assets)){
            return keyBusinessTableByEmpty();
        }
        AtomicInteger number = new AtomicInteger(1);
        return assets.stream()
                .map(item -> KeyBusinessReportBO.builder()
                        .number(String.valueOf(number.getAndIncrement()))
                        .name(item.getName())
                        .version(item.getVersion())
                        .location(item.getLocation())
                        .function(item.getFunction())
                        .build())
                .toList();
    }

    private List<KeyDataReportBO> getKeyDataTable(String systemId){
        List<KeyDataDTO> assets = this.assetService.findKeyData("",systemId)
                .stream()
                .sorted(Comparator.comparing((kd)->Objects.nonNull(kd.getOwnedApp())?kd.getOwnedApp():kd.getData()))
                .toList();
        if(CollectionUtils.isEmpty(assets)){
            return keyDataTableByEmpty();
        }
        AtomicInteger number = new AtomicInteger(1);
        return assets.stream()
                .map(item -> KeyDataReportBO.builder()
                        .number(String.valueOf(number.getAndIncrement()))
                        .data(item.getData())
                        .desc(item.getDesc())
                        .ownedApp(item.getOwnedApp())
                        .location(item.getLocation())
                        .require(item.getRequire())
                        .build())
                .toList();
    }

    private List<SecurityDocReportBO> getSecurityDocTable(String systemId){
        List<SecurityDocumentDTO> assets = this.securityDocumentService.findSecurityDocument(systemId);
        if(CollectionUtils.isEmpty(assets)){
            return securityDocTableByEmpty();
        }
        AtomicInteger number = new AtomicInteger(1);
        return assets.stream()
                .map(item -> SecurityDocReportBO.builder()
                        .number(String.valueOf(number.getAndIncrement()))
                        .name(item.getName())
                        .content(item.getContent())
                        .build())
                .toList();
    }

    private List<PersonnelReportBO> getPersonnelTable(String systemId){
        List<PersonnelDTO> assets = this.personnelService.findPersonnel(systemId);
        if(CollectionUtils.isEmpty(assets)){
            return personnelTableByEmpty();
        }
        AtomicInteger number = new AtomicInteger(1);
        return assets.stream()
                .map(item -> PersonnelReportBO.builder()
                        .number(String.valueOf(number.getAndIncrement()))
                        .name(item.getName())
                        .role(item.getRole())
                        .desc(item.getDesc())
                        .tel(item.getTel())
                        .build())
                .toList();
    }

    private List<PhyEnvReportBO> phyEnvTableByEmpty(){
        return List.of(PhyEnvReportBO.builder()
                .number("")
                .name("")
                .location("")
                .importance("")
                .build());
    }

    private List<PhySecurityReportBO> phySecurityTableByEmpty(){
        return List.of(PhySecurityReportBO.builder()
                .number("")
                .name("")
                .vendor("")
                .location("")
                .importance("")
                .build());
    }

    private List<PwdProductReportBO> pwdProductTableByEmpty(){
        return List.of(PwdProductReportBO.builder()
                .number("")
                .name("")
                .vendor("")
                .model("")
                .algorithm("")
                .count("")
                .use("")
                .build());
    }

    private List<ServerStorageReportBO> serverStorageTableByEmpty(){
        return List.of(ServerStorageReportBO.builder()
                .number("")
                .name("")
                .vendor("")
                .model("")
                .osName("")
                .virtual("")
                .use("")
                .count("")
                .importance("")
                .build());
    }

    private List<NetworkSecurityReportBO> networkSecurityTableByEmpty(){
        return List.of(NetworkSecurityReportBO.builder()
                .number("")
                .name("")
                .vendor("")
                .model("")
                .use("")
                .count("")
                .importance("")
                .build());
    }

    private List<DatabaseReportBO> databaseTableByEmpty(){
        return List.of(DatabaseReportBO.builder()
                .number("")
                .name("")
                .version("")
                .location("")
                .function("")
                .importance("")
                .build());
    }

    private List<KeyBusinessReportBO> keyBusinessTableByEmpty(){
        return List.of(KeyBusinessReportBO.builder()
                .number("")
                .name("")
                .version("")
                .location("")
                .function("")
                .build());
    }

    private List<KeyDataReportBO> keyDataTableByEmpty(){
        return List.of(KeyDataReportBO.builder()
                .number("")
                .data("")
                .desc("")
                .ownedApp("")
                .location("")
                .require("")
                .build());
    }

    private List<SecurityDocReportBO> securityDocTableByEmpty(){
        return List.of(SecurityDocReportBO.builder()
                .number("")
                .name("")
                .content("")
                .build());
    }

    private List<PersonnelReportBO> personnelTableByEmpty(){
        return List.of(PersonnelReportBO.builder()
                .number("")
                .name("")
                .role("")
                .desc("")
                .tel("")
                .build());
    }
}
